﻿//-----------------------------------------------------------------------
// <copyright file="PrivateMessagesWindow.xaml.cs" company="AFS">
// Copyright (c) AFS. All rights reserved.
//
//    This file is part of Chatbox.
//
//    Chatbox is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Lesser General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    any later version.
//
//    Chatbox is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//    GNU Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public License
//    along with Chatbox. If not, see http://www.gnu.org/copyleft/lesser.html
// </copyright>
//----------------------------------------------------------------------- 
namespace ChatBox.UI.Windows.PrivateMessages
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Web;
    using System.Windows;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media.Animation;

    using ChatBox.DomainObjects.Settings;
    using ChatBox.DomainObjects.XmlFeedObjects;
    using ChatBox.UI;
    using ChatBox.UI.MessageDisplay;
    using ChatBox.UI.ViewModels;
    using ChatBox.Utility;
    using ChatBox.XamlUtility;

    /// <summary>
    /// Interaction logic for PrivateMessagesWindow.xaml
    /// </summary>
    public partial class PrivateMessagesWindow : Window
    {
        /// <summary>
        /// Storyboard to show the speak area
        /// </summary>
        private Storyboard showSettingsAnimation;

        /// <summary>
        /// Storyboard to hide the speak area
        /// </summary>
        private Storyboard hideSettingsAnimation;
        
        /// <summary>
        /// Initializes a new instance of the <see cref="PrivateMessagesWindow"/> class.        
        /// </summary>
        public PrivateMessagesWindow()
        {
            this.InitializeComponent();

            this.InitializeStoryboards();
        }

        /// <summary>
        /// Gets or sets a value indicating whether to hide or actually close
        /// </summary>
        public bool HideOnClose { get; set; }

        /// <summary>
        /// Gets the window's attached view model
        /// </summary>
        public PrivateMessagesViewModel ViewModel
        {
            get
            {
                return this.DataContext as PrivateMessagesViewModel;
            }
        }

        /// <summary>
        /// Set the font size
        /// </summary>
        /// <param name="fontSize">the new font size</param>
        public void SetFontSize(double fontSize)
        {
            this.ViewModel.SetFontSize(fontSize);
        }
        
        /// <summary>
        /// Initialize the view models
        /// </summary>
        /// <param name="parentHyperlinkContext">the hperlink context</param>
        public void InitializeViewModel(HyperlinkContext parentHyperlinkContext)
        {
            this.ViewModel.PropertyChanged += this.ViewModelPropertyChanged;

            this.ViewModel.ScrollToBottom = new DocumentViewerScrollToBottom(this.messagesDocumentViewer);

            HyperlinkContext localHyperlinkContext = new HyperlinkContext(
                    parentHyperlinkContext.SitePrefix,
                    parentHyperlinkContext.RequestNavigate,
                    this.LinkMouseEnter,
                    this.LinkMouseLeave);

            this.ViewModel.MessageFormatter = new MessageFormatter(localHyperlinkContext, this.ViewModel.ChatEngine.Logger);

            this.ViewModel.SendPrivateMessageButtonStyle = this.FindStyle("SendPrivateMessageButtonStyle");
            this.ViewModel.DeleteMessageButtonStyle = this.FindStyle("DeleteMessageButtonStyle");

            // can do this when the viewmodel is attached
            this.ViewModel.StatusText = "Loading private messages";
        }

        /// <summary>
        /// Set up the storyboards 
        /// </summary>
        private void InitializeStoryboards()
        {
            this.showSettingsAnimation = this.FindStoryboard("showSettingsAnimation");
            this.hideSettingsAnimation = this.FindStoryboard("hideSettingsAnimation");

            // Change state when the animation completes
            this.showSettingsAnimation.Completed += (sender, e) =>
            {
                this.ViewModel.SettingsVisibilityState = VisibilityAnimationState.Shown;
            };

            this.hideSettingsAnimation.Completed += (sender, e) =>
            {
                this.ViewModel.SettingsVisibilityState = VisibilityAnimationState.Collapsed;
                this.ViewModel.Filters.WriteSettingsCommand.Execute(this.ViewModel.Filters);
            };
        }

        /// <summary>
        /// View Model property changed event handler
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "SettingsVisibilityState":
                {
                    if (this.ViewModel.SettingsVisibilityState == VisibilityAnimationState.Showing)
                    {
                        this.showSettingsAnimation.Begin();
                        this.showHideSettingsUpDown.IsUp = false;
                    }
                    else if (this.ViewModel.SettingsVisibilityState == VisibilityAnimationState.Hiding)
                    {
                        this.hideSettingsAnimation.Begin();
                        this.showHideSettingsUpDown.IsUp = true;
                    }

                    break;
                }
            }
        }

        /// <summary>
        /// Handler for mouse over a link
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event args</param>
        private void LinkMouseEnter(object sender, MouseEventArgs e)
        {
            Hyperlink link = sender as Hyperlink;
            if ((link != null) && (this.ViewModel != null) && (this.ViewModel.ServerSettingsRepository != null))
            {
                // cache the site prefix string
                if (string.IsNullOrEmpty(this.ViewModel.LinkTitlePrefix))
                {
                    ServerSettingsData settingsData = this.ViewModel.ServerSettingsRepository.ReadSettings();
                    this.ViewModel.LinkTitlePrefix = settingsData.Server + "/title/";
                }

                string url = link.NavigateUri.ToString();
                if (url.StartsWith(this.ViewModel.LinkTitlePrefix, StringComparison.OrdinalIgnoreCase))
                {
                    url = url.TrimPrefix(this.ViewModel.LinkTitlePrefix);

                    // double-decode seems to be necessary. May be because of an error up the line?
                    url = HttpUtility.UrlDecode(url);
                    url = HttpUtility.UrlDecode(url);
                }

                this.ViewModel.LinkPreviewText = url;
            }
        }

        /// <summary>
        /// Handler for mouse no longer over a link
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event args</param>
        private void LinkMouseLeave(object sender, MouseEventArgs e)
        {
            if (this.ViewModel != null)
            {
                this.ViewModel.LinkPreviewText = string.Empty;
            }
        }

        /// <summary>
        /// Click on the "expand settings" button
        /// </summary>
        /// <param name="sender">the message sender</param>
        /// <param name="e">the message params</param>
        private void SettingsUpClick(object sender, EventArgs e)
        {
            this.ViewModel.IsSettingsVisible = true;
        }

        /// <summary>
        /// Click on the "collapse settings" button
        /// </summary>
        /// <param name="sender">the message sender</param>
        /// <param name="e">the message params</param>
        private void SettingsDownClick(object sender, EventArgs e)
        {
            this.ViewModel.IsSettingsVisible = false;
        }

        /// <summary>
        /// when the window is becoming visible
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void WindowIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (this.IsVisible)
            {
                this.ViewModel.WindowBecomesVisible();            
            }
        }

        /// <summary>
        /// Clear filter button click handler
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event param</param>
        private void ClearFilterButtonClick(object sender, RoutedEventArgs e)
        {
            this.ViewModel.ClearFilter();
        }

        /// <summary>
        /// Refresh filter button click handler
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void RefreshButtonClick(object sender, RoutedEventArgs e)
        {
            this.ViewModel.RefreshFilter();
        }

        /// <summary>
        /// Bulk delete button click handler
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void BulkDeleteButtonClick(object sender, RoutedEventArgs e)
        {
            if (this.ViewModel.FilteredMessageList == null)
            {
                // should not happen
                return;
            }

            string deleteQueryMessage = string.Format(
                CultureInfo.InvariantCulture, 
                "Delete {0} messages?",
                this.ViewModel.FilteredMessageList.Count);
            MessageBoxResult result = MessageBox.Show(
                    deleteQueryMessage, "Confirm delete", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation);

            if (result == MessageBoxResult.OK)
            {
                IList<int> messageIds = this.ViewModel.FilteredMessageList.MessageIds();
                this.ViewModel.ChatEngine.MessageDelete.DeleteMessages(messageIds);  
            }
        }

        /// <summary>
        /// when the window is closed just hide it
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void Window_Closing(object sender, CancelEventArgs e)
        {
            this.ViewModel.Filters.WriteSettingsCommand.Execute(this.ViewModel.Filters);

            if (this.HideOnClose)
            {
                this.Visibility = Visibility.Collapsed;
                e.Cancel = true;
            }
        }
        
        /// <summary>
        /// Window closed event handler
        /// </summary>
        /// <param name="sender">the event sender</param>
        /// <param name="e">the event params</param>
        private void Window_Closed(object sender, EventArgs e)
        {
            this.ViewModel.SaveWindowPosition();
        }
    }
}